import lodash from 'lodash'
import { JobAction, JobRecordModel } from './JobRecordModel'

/**
 * 工资段
 *
 * 工人的工资可能会改变，在累加计算之前，
 * 先分成许多段
 */
class SalaryFragment {
  private start: Date
  private end: Date

  constructor(
    start: Date,
    end: Date,
    private leftDays: number,
    private salaryMonthly: number,
  ) {
    this.start = new Date(start)
    this.end = new Date(end)
    this.salaryMonthly = salaryMonthly

    this.start.setHours(0)
    this.start.setMinutes(0)
    this.start.setSeconds(0)

    this.end.setHours(0)
    this.end.setMinutes(0)
    this.end.setSeconds(0)
  }

  /** 工作时间（以天计 */
  workDays() {
    const duration = Math.round(
      (this.end.valueOf() - this.start.valueOf()) / (86400 * 1000),
    )

    // 工作时间包含离职当天
    return duration - this.leftDays + 1
  }

  /** 总薪资 */
  salaryTotal() {
    return Math.floor(this.workDays() * this.salaryMonthly / 30)
  }
}

/**
 * 工资计算模型
 */
export class SalaryModel {
  private records: JobRecordModel[]

  constructor(records: JobRecordModel[]) {
    this.records = lodash.cloneDeep(records)
    this.records.sort((a, b) => a.date.valueOf() - b.date.valueOf())
  }

  /** 工人 */
  worker() {
    return this.records[0].worker!
  }

  /** 最近的就职记录，用来计算：
     *  - 当前工资
     */
  latestStart() {
    const filtered = this.records.filter(x => x.action === JobAction.Start)
    return lodash.last(filtered)
  }

  /**
     * 当前月薪
     */
  currentMonthlySalary() {
    const ls = this.latestStart()
    if (!ls) {
      return 0
    }
    const param = ls.actionParams[0]
    return Number.parseInt(param)
  }

  /**
     * 未结清工作记录
     *
     * 执行结清动作，将会使之前的记录不再计入工作天数。
     * 用于方便将工资分段统计
     */
  unSettledRecords() {
    const filtered = this.records.filter(x => x.action === JobAction.Settlement)
    const lastSettlement = lodash.last(filtered)
    if (!lastSettlement) {
      return this.records
    }
    else {
      const index = this.records.findIndex(x => x === lastSettlement)
      if (index === this.records.length - 1) {
        return []
      }
      else {
        return this.records.slice(index + 1)
      }
    }
  }

  /**
     * 将工作记录进行分组
     *
     * 分组的依据仅仅是入职和离职的记录。
     * 仅仅是为了支持工资变动。
     * 至于开工资被分到哪一组并不重要。
     * 因为并不会分开计算每段的应发未发
     */
  unSettledGroups() {
    const firstRec = this.unSettledRecords()[0]
    if (!firstRec || firstRec.action !== JobAction.Start) {
      return []
    }

    const groups = [] as JobRecordModel[][]
    let index = -1
    for (const record of this.unSettledRecords()) {
      if (record.action === JobAction.Start) {
        index += 1
        groups[index] = []
      }
      groups[index].push(record)
    }

    return groups
  }

  private _fragments() {
    // console.log(
    //     this.unSettledGroups()
    // );

    const res = []
    for (const group of this.unSettledGroups()) {
      const start = group[0].date
      const _endRec = group.find(x => x.action === JobAction.End)
      const end = _endRec ? _endRec.date : new Date(Date.now() - 86400000)
      const salaryMonthly = Number.parseFloat(group[0].actionParams[0])
      const leftDays = group.filter(
        x => x.action === JobAction.Pause,
      ).map(x => Number.parseFloat(x.actionParams[0])).reduce((y, x) => y + x, 0)
      const fragment = new SalaryFragment(start, end, leftDays, salaryMonthly)
      // sum += fragment.salaryTotal()
      res.push(fragment)
    }

    return res
  }

  /** 所有工作日 */
  totalWorkDays() {
    // console.log(
    //     this._fragments()
    // );

    return this._fragments().map(x => x.workDays()).reduce((y, x) => y + x, 0)
  }

  /** 所有薪水（不含奖金处罚 */
  totalSalary() {
    return this._fragments().map(x => x.salaryTotal()).reduce((y, x) => y + x, 0)
  }

  /** 所有奖金 */
  totalBonus() {
    return this.unSettledRecords().filter(
      x => x.action === JobAction.Bonus,
    ).map(x => Number.parseInt(x.actionParams[0])).reduce((y, x) => y + x, 0)
  }

  /** 所有处罚 */
  totalBlame() {
    return this.unSettledRecords().filter(
      x => x.action === JobAction.Blame,
    ).map(x => Number.parseInt(x.actionParams[0])).reduce((y, x) => y + x, 0)
  }

  /** 总计应发 = 薪水 + 奖金 - 罚金 */
  totalShouldSent() {
    return this.totalSalary() - this.totalBlame() + this.totalBonus()
  }

  /** 所有支取 */
  totalAdvance() {
    return this.unSettledRecords().filter(
      x => x.action === JobAction.Advance,
    ).map(x => Number.parseInt(x.actionParams[0])).reduce((y, x) => y + x, 0)
  }

  /** 剩余未发 */
  totalShouldSentRemaining() {
    return this.totalShouldSent() - this.totalAdvance()
  }
}
